/***************************************************************************
 *   Copyright (C) 2007 by Leonid Krashenko   *
 *   Leonid.Krashenko@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef _nsNodes_
#define _nsNodes_

#include <string>
#include <vector>

#include "neiderra/core/iException.h"

using std::vector;
using std::string;

namespace neiderra
{
	namespace utils
	{
		namespace script
		{
			class nsAsmGenerator;
			class Symtable;
			
			union numvalues{
				int ival;
				float fval;
				double dval;
				char cval;
				bool bval;
			};

			enum op_type {
				OT_ASSIGN,
				OT_PLUS,
 				OT_MINUS,
 				OT_MULT,
 				OT_DIV,
 				OT_PARAM, 
 				OT_RETURN,
	 			OT_DEREF		// dereferencing (a.b)
			};

			struct nsClass;
			struct nsField;
			struct nsMethod;
			struct nsFCall;
			struct nsSelfRef;

			struct nsNode
			{
				nsNode();
			
				virtual ~nsNode()
				{}
			
				nsNode* parent;
				static Symtable* symtab;
				
				virtual void traverse(nsAsmGenerator* tr);
			
				virtual unsigned size()	{ return _size;	}
				virtual void setSize(unsigned n) { _size = n; }
				virtual unsigned getSize() { return _size; }

				virtual void setParent(nsNode* parent);
				virtual nsNode* getParent();
				virtual void setType(nsClass* type);
				virtual nsClass* getType();
				virtual void setName(const string& name);
				virtual string getName();
				virtual void setShortName(const string& name);
				virtual string getShortName();

			protected:
				string name;
				nsClass* type;
				string _shortName;
				unsigned _size;
			};
			
			struct nsNodes: public nsNode {
				nsNodes();
				virtual ~nsNodes();
				
				// traverse manipulations
				virtual void traverse(nsAsmGenerator*);

				// adds a node to collection
				virtual void add(nsNode*);
				// get node by index
				virtual nsNode* getByNum(int i);
				// get node by full name (like '$A$x')
				virtual nsNode* getByName(const string& name);
				// get node by short name (like 'x')
				virtual nsNode* getByShortName(const string& name);
				// remove node from collection
				virtual void remove(nsNode*);
				// clear collection
				virtual void clear();
				// returns true if node is in the collection
				virtual bool find(nsNode*);

				// get size of collection
				int count(){ return (int) nodes.size(); }

				// get size of collection in bytes
				virtual unsigned size();

				vector<nsNode*> nodes;
			};

			struct nsDecFunction: public nsNode {
				virtual void traverse(nsAsmGenerator*);
			};
			
			struct nsOperand: public nsNode{ 
				virtual void traverse(nsAsmGenerator*);

				string stype;
			};
			
			struct nsRef: public nsOperand {
				nsRef();
				virtual void traverse(nsAsmGenerator*);
				
				// set reference to object
				virtual void setRef(nsOperand*);
				// get reference ti object
				virtual nsOperand* getRef() { return object; }
				virtual unsigned int getSize() { 
					if(object != 0)
						return object->getSize();
					else return this->_size;
				}

				nsOperand* object;

			};

			struct nsSelfRef: public nsRef {
				nsSelfRef();

				virtual void traverse(nsAsmGenerator* tr);
			};

			struct nsVar: public nsOperand{
				nsVar();
				virtual void traverse(nsAsmGenerator*);

				inline bool isLocal() { return _isLocal; }
				void setIsLocal(bool f) { _isLocal = f; }
				bool isPointer();

			private:
				bool _isLocal;
			};

			// fixme: var declaration can't be nsOperand
			struct nsVarDec: public nsVar{
				nsVarDec();
				virtual void traverse(nsAsmGenerator*);
				inline bool isField() { return _isField; }
				void setIsField(bool f) { _isField = f; }
			private:
				bool _isField;
			};
			
			struct nsNumber: public nsOperand{
				nsNumber();

				numvalues value;	
				virtual void traverse(nsAsmGenerator*);
			};

			struct nsBlock: public nsNodes {
				nsNodes* stmts;
				virtual unsigned size() { return stmts->size(); }
				virtual void traverse(nsAsmGenerator*);
				virtual nsNodes* getStmtList() { return stmts; }
				virtual void setStmtList(nsNodes* list) { stmts = list; }
			};


			struct nsFunc: public nsOperand{
				nsFunc();

				nsNodes* params;
				nsBlock* body;	// code

				virtual void traverse(nsAsmGenerator*);
				virtual nsNodes* collect_decs();

				virtual void setParams(nsNodes* params) { this->params = params; }
				virtual nsNodes* getParams() { return params; }

				virtual void setBody(nsBlock* body) { this->body = body; }
				virtual nsBlock* getBody() { return body; }

				// true if the function is a method
				inline bool isMethod() { return _isMethod; }
				// tell the function if it is a method
				void setIsMethod(bool f) { _isMethod = true; }

				nsNodes& getLocals() { return _locals; }
				void addLocal(nsNode* n) { _locals.add(n); }

			protected:
				nsNodes _locals;	// local declarations & formal args
				bool _isMethod;
			};
			
			// todo: replace nsVarDecs and nsFuncs in class declarations
			// with nsFields and nsMethods
			struct nsField: public nsVar{
				nsField(): nsVar() {}
				virtual void traverse(nsAsmGenerator*);
			};

//			typedef nsNodesCollection<nsField*> nsFields;
			
			struct nsMethod: public nsFunc{
				nsMethod(): nsFunc() {}
				virtual void traverse(nsAsmGenerator*);
			};

//			typedef nsNodesCollection<nsMethod*> nsMethods;

			struct nsClass: public nsNode {
				nsClass(): nsNode() { _embedded = false; }
				virtual void traverse(nsAsmGenerator*);

				nsNodes methods;
				nsNodes fields;
				//nsNodesCollection<nsMethod*> methods;
				//nsNodesCollection<nsField*> fields;

				// set true if the type is embedded
				void setEmbedded(bool f) { _embedded = f; }
				// true if the type is embedded
				inline bool isEmbedded() { return _embedded; }
				// get field node by full name (like '$A$x')
				nsField* getFieldByName(const string& fieldName);
				// get method node by full name (like '$A$f')
				nsMethod* getMethodByName(const string& methodName);
				// get field node by short name (like 'x')
                nsField* getFieldByShortName(const string& fieldName);
				// get method node by short name (like 'f')
				nsMethod* getMethodByShortName(const string& methodName);
				// add field node
				void addField(nsField* fieldNode);
				// add method node
                void addMethod(nsMethod* methodNode);
				// get fields collection
				nsNodes& getFields() { return fields; }
				// get methods collection
				nsNodes& getMethods() { return methods; }

				virtual unsigned size();
				virtual unsigned getSize() { return size(); }

			protected:
				// extract class name from the member name
				string extractClassName(const string& memberName);
				bool _embedded;
			};
			
			struct nsExpr: public nsOperand{
				nsOperand* left, *right;
				op_type operation;
				virtual void traverse(nsAsmGenerator*);
				virtual nsOperand* getLeft() { return left; }
				virtual nsOperand* getRight() { return right; }
				virtual void setLeft(nsOperand* left) { this->left = left; }
				virtual void setRight(nsOperand* right) { this->right = right; }
				virtual void setOperationType(op_type operation) { this->operation = operation; }
				virtual op_type getOperationType() { return operation; }
			};

			struct nsArg: public nsVar
			{
				nsArg();
				virtual void traverse(nsAsmGenerator*);
			};

			struct nsAArg: public nsExpr
			{
				virtual void traverse(nsAsmGenerator*);
			};

			struct nsFCall: public nsFunc{
				nsFCall();
				virtual void traverse(nsAsmGenerator*);
			};

			struct nsMethodCall: public nsFCall {
				nsMethodCall();
				virtual void traverse(nsAsmGenerator*);
				
//				void setArgs(nsNodes* args) { _args = args; }
//				nsNodes* getArgs() { return _args; }
			private:
//				nsNodes* _args;
			};

			struct nsRetStmt: public nsExpr
			{
				nsRetStmt();
				virtual void traverse(nsAsmGenerator*);
			};

			struct nsStmt: public nsNode{
				nsOperand* lval;
				nsExpr* rval;
			};

		}
	}
}

#endif
